home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 85 / CD Temático 40 Febrero 2004.iso / DOS / testdisk / src / fnctdsk.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-01-09  |  13.8 KB  |  504 lines

  1. /*
  2.  
  3.     File: fnctdsk.c
  4.  
  5.     Copyright (C) 1998-2004 Christophe GRENIER <grenier@cgsecurity.org>
  6.   
  7.     This software is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.   
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.   
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.  */
  22.  
  23.  
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "types.h"
  28. #include "common.h"
  29. #include "fnctdsk.h"
  30. #include "lang.h"
  31. #include "testdisk.h"
  32. #include "intrface.h"
  33. #include "analyse.h"
  34.  
  35. static void store4_little_endian(unsigned char *cp, unsigned int val)
  36. {
  37.   cp[0] = (val & 0xff);
  38.   cp[1] = ((val >> 8) & 0xff);
  39.   cp[2] = ((val >> 16) & 0xff);
  40.   cp[3] = ((val >> 24) & 0xff);
  41. }
  42.  
  43. static unsigned int read4_little_endian(const unsigned char *cp)
  44. {
  45.   return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8) + ((unsigned int)(cp[2]) << 16) + ((unsigned int)(cp[3]) << 24);
  46. }
  47.  
  48. unsigned int get_start_sect(const struct partition_dos *p)
  49. {
  50.   return read4_little_endian(p->start4);
  51. }
  52.  
  53. unsigned int get_nr_sects(const struct partition_dos *p)
  54. {
  55.   return read4_little_endian(p->size4);
  56. }
  57.  
  58. static void set_nr_sects(struct partition_dos *p, unsigned int nr_sects)
  59. {
  60.   store4_little_endian(p->size4, nr_sects);
  61. }
  62.  
  63. static void set_start_sect(struct partition_dos *p, unsigned int start_sect)
  64. {
  65.   store4_little_endian(p->start4, start_sect);
  66. }
  67.  
  68. dword CHS2LBA(const t_param_disk *disk_car,const t_CHS*CHS)
  69. { return ((dword)CHS->cylinder*(disk_car->CHS.head+1)+CHS->head)*disk_car->CHS.sector+CHS->sector-1;
  70. }
  71.  
  72. dword C_H_S2LBA(const t_param_disk *disk_car,const word C, const byte H, const byte S)
  73. { return ((dword)C*(disk_car->CHS.head+1)+H)*disk_car->CHS.sector+S-1;
  74. }
  75.  
  76. unsigned int LBA2sector(const t_param_disk *disk_car, const dword sect)
  77. { return (sect%disk_car->CHS.sector)+1; }
  78.  
  79. unsigned int LBA2head(const t_param_disk *disk_car, const dword sect)
  80. { return (sect/disk_car->CHS.sector)%(disk_car->CHS.head+1); }
  81.  
  82. unsigned int LBA2cylinder(const t_param_disk *disk_car, const dword sect)
  83. { return (sect/disk_car->CHS.sector)/(disk_car->CHS.head+1); }
  84.  
  85. void LBA2CHS(const t_param_disk *disk_car,const dword lba, t_CHS*CHS)
  86. {
  87.   dword pos=lba;
  88.   CHS->sector=(pos%disk_car->CHS.sector)+1;
  89.   pos/=disk_car->CHS.sector;
  90.   CHS->head=pos%(disk_car->CHS.head+1);
  91.   CHS->cylinder=pos/(disk_car->CHS.head+1);
  92. }
  93.  
  94. void dup_t_CHS(t_CHS * CHS_dest, const t_CHS * CHS_source)
  95. {
  96.   CHS_dest->cylinder=CHS_source->cylinder;
  97.   CHS_dest->head=CHS_source->head;
  98.   CHS_dest->sector=CHS_source->sector;
  99. }
  100.  
  101. void dup_t_diskext(t_diskext *dest, const t_diskext *src)
  102. {
  103.   dest->lba=src->lba;
  104.   dest->boot_sector=src->boot_sector;
  105.   dest->blocksize=src->blocksize;
  106.   dest->part_type=src->part_type;
  107.   dest->upart_type=src->upart_type;
  108.   dest->part_size=src->part_size;
  109.   dest->status=src->status;
  110.   dest->order=src->order;
  111.   strncpy(dest->info,src->info,sizeof(dest->info));
  112.   strncpy(dest->name,src->name,sizeof(dest->name));
  113. }
  114.  
  115. void partition2entry(const t_param_disk *disk_car, const dword pos, const t_diskext *partition, struct partition_dos *p)
  116. {
  117.   t_CHS start,end;
  118.   LBA2CHS(disk_car,partition->lba,&start);
  119.   LBA2CHS(disk_car,partition->lba+partition->part_size-1,&end);
  120.   if(partition->status==STATUS_PRIM_BOOT)
  121.     p->boot_ind=0x80;
  122.   else
  123.     p->boot_ind=0;             /* Non bootable */
  124.   p->sys_ind=partition->part_type;
  125.   set_start_sect(p,partition->lba-pos);
  126.   if(start.cylinder>1023)
  127.   { /* Partition Magic 5 uses CHS=(1023,0,1) if extended or last logical *
  128.      * Linux fdisk and TestDisk use CHS=(1023,lastH,lastS)               */
  129.     p->head=(unsigned char)disk_car->CHS.head;
  130.     p->sector=(unsigned char)(disk_car->CHS.sector|((1023>>8)<<6));
  131.     p->cyl=(unsigned char)1023;
  132.   }
  133.   else
  134.   {
  135.     p->head=(unsigned char)start.head;
  136.     p->sector=(unsigned char)(start.sector|((start.cylinder>>8)<<6));
  137.     p->cyl=(unsigned char)(start.cylinder);
  138.   }
  139.   if(end.cylinder>1023)
  140.   {
  141.     p->end_head=(unsigned char)disk_car->CHS.head;
  142.     p->end_sector=(unsigned char)(disk_car->CHS.sector|((1023>>8)<<6));
  143.     p->end_cyl=(unsigned char)1023;
  144.   }
  145.   else
  146.   {
  147.     p->end_head=(unsigned char)end.head;
  148.     p->end_sector=(unsigned char)(end.sector|((end.cylinder>>8)<<6));
  149.     p->end_cyl=(unsigned char)end.cylinder;
  150.   }
  151.   set_nr_sects(p,partition->part_size);
  152. }
  153.  
  154. int is_extended(const unsigned int part_type)
  155. {
  156.   return (part_type==(unsigned char)P_EXTENDX || part_type==(unsigned char)P_EXTENDED || part_type==(unsigned char)P_LINUXEXTENDX);
  157. }
  158.  
  159. int entry2partition(t_param_disk *disk_car, const dword pos, t_diskext *partition, const struct partition_dos *p, const status_type_t status,const unsigned int order,const int debug)
  160. {
  161.   t_CHS start,end;
  162.   t_CHS start_calculated,end_calculated;
  163.   partition_reset(partition);
  164.   partition->part_type=p->sys_ind;
  165.   partition->lba=pos+get_start_sect(p);
  166.   partition->order=order;
  167.   partition->part_size=get_nr_sects(p);
  168.  
  169.   LBA2CHS(disk_car,partition->lba,&start_calculated);
  170.   LBA2CHS(disk_car,partition->lba+partition->part_size-1,&end_calculated);
  171.  
  172.  
  173.   start.cylinder=s_cyl(p);
  174.   start.head=s_head(p);
  175.   start.sector=s_sect(p);
  176.   end.cylinder=e_cyl(p);
  177.   end.head=e_head(p);
  178.   end.sector=e_sect(p);
  179.   switch(status)
  180.   {
  181.     case STATUS_PRIM:
  182.       if(is_extended(partition->part_type))
  183.       {
  184.     partition->status=STATUS_EXT;
  185.     partition->upart_type=UP_EXTENDED;
  186.       }
  187.       else
  188.     if(p->boot_ind!=0)
  189.       partition->status=STATUS_PRIM_BOOT;
  190.     else
  191.       partition->status=status;
  192.       break;
  193.     default:
  194.       partition->status=status;
  195.       break;
  196.   }
  197.   /* Check CHS */
  198.   if((start.sector==0)||(start.sector>disk_car->CHS.sector))
  199.   {
  200.     partition->errcode=BAD_SS;
  201.     return 1;
  202.   }
  203.   if((end.sector==0)||(end.sector>disk_car->CHS.sector))
  204.   {
  205.     partition->errcode=BAD_ES;
  206.     return 1;
  207.   }
  208.   if(start.head>disk_car->CHS.head)
  209.   {
  210.     partition->errcode=BAD_SH;
  211.     return 1;
  212.   }
  213.   if(start.cylinder>disk_car->CHS.cylinder)
  214.   {
  215.     partition->errcode=BAD_SC;
  216.     return 1;
  217.   }
  218.   if(end.head>disk_car->CHS.head)
  219.   {
  220.     partition->errcode=BAD_EH;
  221.     return 1;
  222.   }
  223.   if(end.cylinder>disk_car->CHS.cylinder)
  224.   {
  225.     partition->errcode=BAD_EC;
  226.     return 1;
  227.   }
  228.   /* */
  229.  
  230.   if(((start_calculated.cylinder<=1023)&& (C_H_S2LBA(disk_car,start.cylinder,start.head,start.sector)!=partition->lba))
  231.     || ((start_calculated.cylinder>1023)&&(start.cylinder!=1023)&&(start.cylinder!=(start_calculated.cylinder&1023))))
  232.   {
  233.       ecrit_rapport("BAD_RS LBA=%ld %ld\n",partition->lba,C_H_S2LBA(disk_car,start.cylinder,start.head,start.sector));
  234.       partition->errcode=BAD_RS;
  235.       return 1;
  236.   }
  237.  
  238.   if(((end_calculated.cylinder<=1023)&& (C_H_S2LBA(disk_car,end.cylinder,end.head,end.sector)!=partition->lba+partition->part_size-1))
  239.      || ((end_calculated.cylinder>1023)&&(end.cylinder!=1023)&&(end.cylinder!=(end_calculated.cylinder&1023))))
  240.   {
  241.     partition->errcode=BAD_SCOUNT;
  242.     return 1;
  243.   }
  244.   /* Check partition and load partition name */
  245.   check_part(disk_car,debug,partition);
  246.   return 0;
  247. }
  248.  
  249. const char* errmsg_entry2partition(const errcode_type_t errcode)
  250. {
  251.   switch(errcode)
  252.   {
  253.     case BAD_SS: return msg_BAD_S_SECT;
  254.     case BAD_ES: return msg_BAD_E_SECT;
  255.     case BAD_SH: return msg_BAD_S_HEAD;
  256.     case BAD_EH: return msg_BAD_E_HEAD;
  257.     case BAD_EBS: return msg_END_BFR_START;
  258.     case BAD_RS: return msg_BAD_RS;
  259.     case BAD_SC: return msg_BAD_S_CYL;
  260.     case BAD_EC: return msg_BAD_E_CYL;
  261.     case BAD_SCOUNT: return msg_BAD_SCOUNT;
  262.     case BAD_NOERR: return "";
  263.   }
  264.   ecrit_rapport("errmsg_entry2partition: unhandled error\n");
  265.   return "";
  266. }
  267.  
  268. int read_MBR(t_param_disk *disk_car,void *buffer)
  269. {
  270.   if(disk_car->read(disk_car,1, buffer, 0))
  271.   {
  272.     wdoprintf(stdscr,msg_PART_RD_ERR);
  273.     return 1;
  274.   }
  275.   return 0;
  276. }
  277.  
  278. int write_MBR(t_param_disk *disk_car,void *buffer)
  279. {
  280.   if(disk_car->write(disk_car,1, buffer, 0))
  281.   {
  282.     wdoprintf(stdscr,msg_PART_WR_ERR);
  283.     return 1;
  284.   }
  285.   return 0;
  286. }
  287.  
  288. t_list_disk *insert_new_disk(t_list_disk *list_disk, t_param_disk *disk_car)
  289. {
  290.   if(disk_car==NULL)
  291.     return list_disk;
  292.   {
  293.     t_list_disk *prev;
  294.     t_list_disk *new_disk=(t_list_disk *)MALLOC(sizeof(*new_disk));
  295.     new_disk->disk=disk_car;
  296.     /* Add it at the end */
  297.     for(prev=list_disk;prev && prev->next;prev=prev->next);
  298.     if(prev!=NULL)
  299.     {
  300.       prev->next=new_disk;
  301.     }
  302.     new_disk->prev=prev;
  303.     new_disk->next=NULL;
  304.     return (list_disk!=NULL?list_disk:new_disk);
  305.   }
  306. }
  307.  
  308. t_list_part *insert_new_partition(t_list_part *list_part, t_diskext *part)
  309. {
  310.   return insert_new_partition_aux(list_part, element_new(part));
  311. }
  312.  
  313. t_list_part *insert_new_partition_aux(t_list_part *list_part, t_list_part *new_element)
  314. { /* new partition musn't be used after insert !*/
  315.   t_list_part *prev=NULL;
  316.   t_list_part *next;
  317.   for(next=list_part;;next=next->next)
  318.   { /* prev new next */
  319.     if((next==NULL)||(new_element->part->lba<next->part->lba)||((new_element->part->lba==next->part->lba)&&(new_element->part->part_size<=next->part->part_size)))
  320.     {
  321.       if((next!=NULL)&&(next->part->lba==new_element->part->lba)&&(next->part->part_size==new_element->part->part_size)&&(next->part->part_type==new_element->part->part_type)&&(next->part->upart_type==new_element->part->upart_type))
  322.       {
  323.     FREE(new_element->part);
  324.     FREE(new_element);
  325.     return list_part;
  326.       }
  327.       else
  328.       { /* prev new_element next */
  329.     new_element->next=next;
  330.     new_element->prev=prev;
  331.     if(next!=NULL)
  332.       next->prev=new_element;
  333.     if(prev!=NULL)
  334.     {
  335.       prev->next=new_element;
  336.       return list_part;
  337.     }
  338.     return new_element;
  339.       }
  340.     }
  341.     prev=next;
  342.   }
  343.   ecrit_rapport("insert_new_partition_aux : BUG!\n");
  344.   exit(EXIT_FAILURE);
  345. }
  346.  
  347. int check_list_part(t_list_part *list_part)
  348. {
  349.   t_list_part *prev=NULL;
  350.   t_list_part *parts;
  351.   if((list_part!=NULL) && (list_part->prev!=NULL))
  352.   {
  353.     ecrit_rapport("\ncheck_list_part error: list_part->prev!=NULL\n");
  354.     exit(EXIT_FAILURE);
  355.   }
  356.   for(parts=list_part;parts!=NULL;parts=parts->next)
  357.   {
  358. /*ecrit_rapport("%p %p %p\n",parts->prev, parts, parts->next); */
  359.     if(prev!=parts->prev)
  360.     {
  361.       ecrit_rapport("\ncheck_list_part error: prev!=parts->prev\n");
  362.       exit(EXIT_FAILURE);
  363.     }
  364.     prev=parts;
  365.   }
  366.   if((prev!=NULL) && (prev->next!=NULL))
  367.   {
  368.     ecrit_rapport("\ncheck_list_part error: prev->next!=NULL\n");
  369.     exit(EXIT_FAILURE);
  370.   }
  371.   return 0;
  372. }
  373.  
  374. t_list_part *sort_list_part(t_list_part *list_part)
  375. {
  376.   t_list_part *new_list_part=NULL;
  377.   t_list_part *element;
  378.   t_list_part *next;
  379.   for(element=list_part;element!=NULL;element=next)
  380.   {
  381.     next=element->next;
  382.     new_list_part=insert_new_partition_aux(new_list_part,element);
  383.   }
  384.   return new_list_part;
  385. }
  386.  
  387. void delete_list_part(t_list_part *list_part)
  388. {
  389.   t_list_part *element;
  390.   /* Libere la memoire */
  391.   element=list_part;
  392.   while(element!=NULL)
  393.   {
  394.     t_list_part *next=element->next;
  395.     FREE(element->part);
  396.     FREE(element);
  397.     element=next;
  398.   }
  399. }
  400.  
  401. void  partition_reset(t_diskext *partition)
  402. {
  403. /* partition->lba=0; Don't reset lba, used by search_part */
  404.   partition->part_size=0;
  405.   partition->boot_sector=0;
  406.   partition->blocksize=0;
  407.   partition->part_type=P_NO_OS;
  408.   partition->upart_type=UP_UNK;
  409.   partition->status=STATUS_DELETED;
  410.   partition->order=0;
  411.   partition->errcode=BAD_NOERR;
  412.   partition->name[0]='\0';
  413.   partition->info[0]='\0';
  414. }
  415.  
  416. t_diskext *partition_new()
  417. {
  418.   t_diskext *partition=(t_diskext *)MALLOC(sizeof(*partition));
  419.   partition_reset(partition);
  420.   return partition;
  421. }
  422.  
  423. t_list_part *element_new(t_diskext *part)
  424. {
  425.   t_list_part *new_element=(t_list_part*)MALLOC(sizeof(*new_element));
  426.   new_element->part=part;
  427.   new_element->prev=new_element->next=NULL;
  428.   new_element->to_be_removed=0;
  429.   return new_element;
  430. }
  431.  
  432. int can_be_ext(const t_param_disk *disk_car, t_diskext *partition)
  433. {
  434.   return((LBA2head(disk_car,partition->lba)>0)&&
  435.       (LBA2cylinder(disk_car,partition->lba)!=0 ||
  436.        LBA2head(disk_car,partition->lba)!=1 ||
  437.        LBA2sector(disk_car,partition->lba)!=1));
  438. }
  439.  
  440. int test_structure(t_list_part *list_part)
  441. { /* Return 1 if bad*/
  442.   int nbr_prim=0, nbr_prim_boot=0, nbr_log_block=0;
  443.   t_list_part *first_log=NULL;
  444.   t_list_part *new_list_part=NULL;
  445.   t_list_part *element;
  446.   t_list_part *new_element;
  447.   int res=0;
  448.   for(element=list_part;element!=NULL;element=element->next)
  449.   {
  450.     switch(element->part->status)
  451.     {
  452.       case STATUS_LOG:
  453.       if(first_log==NULL)
  454.       {
  455.         first_log=element;
  456.         nbr_log_block++;
  457.       }
  458.     if(is_extended(element->part->part_type))
  459.           return 1;
  460.     break;
  461.       case STATUS_PRIM_BOOT:
  462.     if(nbr_prim_boot++)
  463.       return 1;
  464.       case STATUS_PRIM:
  465.     nbr_prim++;
  466.     first_log=NULL;
  467.     break;
  468.       case STATUS_DELETED:
  469.     break;
  470.       default:
  471.     ecrit_rapport("test_structure: severe error\n");
  472.     break;
  473.     }
  474.   }
  475.   if(nbr_log_block>1 || nbr_log_block+nbr_prim>4)
  476.     return 1;
  477.   /* Sort list_part in new_list_part */
  478.   for(element=list_part;element!=NULL;element=element->next)
  479.   {
  480.     if(element->part->status!=STATUS_DELETED)
  481.       new_list_part=insert_new_partition(new_list_part,element->part);
  482.   }
  483.   /* Test chevauchement */
  484. /* ecrit_rapport("\nTest chevauchement\n"); */
  485.   for(element=new_list_part;element!=NULL;element=element->next)
  486.   {
  487. /*   ecrit_rapport("start %lu, end %lu\n", element->part->lba,element->part->lba+element->part->part_size-1); */
  488.     if(((element->prev!=NULL) && (element->part->lba<=element->prev->part->lba+element->prev->part->part_size-1)) ||
  489.     ((element->next!=NULL) && (element->part->lba+element->part->part_size-1>=element->next->part->lba)))
  490.     {
  491. /*     ecrit_rapport("\nChevauchement\n"); */
  492.       res=1;
  493.     }
  494.   }
  495. /* ecrit_rapport("Test chevauchement fin\n"); */
  496.   for(element=new_list_part;element!=NULL;element=new_element)
  497.   {
  498.     new_element=element->next;
  499.     FREE(element);
  500.   }
  501.   return res;
  502. }
  503.  
  504.